package pt.iscte.dcti.es.rhplus.servico;

import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;

import pt.iscte.dcti.es.rhplus.sistema.UtensiliosParaStrings;
import pt.iscte.dcti.es.rhplus.sistema.persistencia.AcessoBD;

/**
 * 
 * @author Gustavo Cabral
 * @author Helena Monteiro
 * @author Joao Catarino
 * @author Tiago Moreiras
 */
public class Pagamento {

	public Pagamento(final int id_pagamento, final LinkedList<Servico> lista_de_servicos, final String tipo, final Date data,
			final String numero_de_cheque, final String tipo_de_cartao, final String numero_de_cartao, final Date data_de_validade_do_cartao) {
		this.id_pagamento = id_pagamento;
		this.lista_de_servicos = lista_de_servicos;
		this.tipo = tipo;
		this.data = data;
		this.numero_de_cheque = numero_de_cheque;
		this.tipo_de_cartao = tipo_de_cartao;
		this.numero_de_cartao = numero_de_cartao;
		this.data_de_validade_do_cartao = data_de_validade_do_cartao;
	}

	public Pagamento(final int id_pagamento, final LinkedList<Servico> lista_de_servicos, final String tipo, final Date data,
			final String numero_de_cheque, final String tipo_de_cartao, final String numero_de_cartao, final Date data_de_validade_do_cartao,
			final Factura factura) {
		this.id_pagamento = id_pagamento;
		this.lista_de_servicos = lista_de_servicos;
		this.tipo = tipo;
		this.data = data;
		this.numero_de_cheque = numero_de_cheque;
		this.tipo_de_cartao = tipo_de_cartao;
		this.numero_de_cartao = numero_de_cartao;
		this.data_de_validade_do_cartao = data_de_validade_do_cartao;
		this.factura = factura;
	}

	public int getIdPagamento() {
		return id_pagamento;
	}

	public LinkedList<Servico> getListaDeServicos() {
		return lista_de_servicos;
	}

	public String getTipo() {
		return tipo;
	}

	public Date getData() {
		return data;
	}

	public double getValorTotal() {
		double valor_total = 0;
		for (Servico servico : lista_de_servicos) {
			valor_total = valor_total + servico.getPreco() * (1 - servico.getPercentagem());
		}

		return valor_total;
	}

	public String getNumeroDeCheque() {
		return numero_de_cheque;
	}

	public String getTipoDeCartao() {
		return tipo_de_cartao;
	}

	public String getNumeroDeCartao() {
		return numero_de_cartao;
	}

	public Date getDataDeValidadeDoCartao() {
		return data_de_validade_do_cartao;
	}

	public Factura getFactura() {
		return factura;
	}

	public boolean temFacturaEmitida() {
		return factura != null;
	}

	public LinkedList<Servico> getServicos() {
		return this.lista_de_servicos;
	}

	public void adicionaServico(final int id_servico) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {

		Servico servico = Servico.devolve(id_servico);
		servico.paga(this.getIdPagamento());
		this.lista_de_servicos.add(servico);
		servico.gravaParaBaseDeDados();
	}

	public Servico devolveServico(final int id_servico) {
		// Procura o servico associada ao identificador.
		Iterator<Servico> iterator = lista_de_servicos.iterator();
		while (iterator.hasNext()) {
			Servico servico = iterator.next();
			if (servico.equals(id_servico))
				return servico;
		}

		// Se o Servico nao foi encontrado devolve null.
		return null;
	}

	public void removeServico(final int id_servico) {
		// Procura o servico associada ao identificador.
		Iterator<Servico> iterator = lista_de_servicos.iterator();
		while (iterator.hasNext()) {
			Servico servico = iterator.next();
			if (servico.equals(id_servico)) {
				servico.removePagamento();
				iterator.remove();
			}
		}
	}

	public void emiteFactura() throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {
		Factura.insere(this.data, this.id_pagamento);
	}

	public static Pagamento devolve(final int id_pagamento) throws SQLException, ClassNotFoundException, InstantiationException,
			IllegalAccessException {

		// Consulta a BD
		AcessoBD acesso_bd = new AcessoBD();
		acesso_bd.carregaDriverEAbreLigacao();
		String qryName = new String("devolver_pagamento");
		Hashtable<String, Object> dados_da_factura = new Hashtable<String, Object>();
		dados_da_factura.put("var_id_pagamento", id_pagamento);
		ResultSet result_set = acesso_bd.executaSelect(qryName, dados_da_factura);

		if (result_set.next()) {

			// Cria o servico generico

			Factura factura = Factura.devolve(id_pagamento);

			String tipo = result_set.getString("tipo_pagamento");
			String numero_de_cheque = result_set.getString("numero_de_cheque");
			String tipo_de_cartao = result_set.getString("tipo_de_cartao");
			String numero_de_cartao = result_set.getString("numero_de_cartao");
			Date data = result_set.getDate("data");
			Date data_de_validade_do_cartao = result_set.getDate("data_de_validade_do_cartao");

			acesso_bd.fechaLigacao();

			LinkedList<Servico> lista_de_servicos = Servico.devolveTodosDoPagamento(id_pagamento);
			Pagamento pagamento = new Pagamento(id_pagamento, lista_de_servicos, tipo, data, numero_de_cheque, tipo_de_cartao, numero_de_cartao,
					data_de_validade_do_cartao, factura);

			return pagamento;
		} else
			return null;
	}

	public static void insere(final Hashtable<String, Object> dados_do_pagamento) throws SQLException, ClassNotFoundException,
			InstantiationException, IllegalAccessException {

		AcessoBD acesso_bd = new AcessoBD();
		acesso_bd.carregaDriverEAbreLigacao();
		String qryName = new String("inserir_pagamento");
		acesso_bd.executaUpdate(qryName, dados_do_pagamento);
		acesso_bd.fechaLigacao();

	}

	public static void remove(final int id_pagamento) throws SQLException, ClassNotFoundException, InstantiationException, IllegalAccessException {

		AcessoBD acesso_bd = new AcessoBD();
		acesso_bd.carregaDriverEAbreLigacao();
		String qryName = new String("remover_pagamento");
		Hashtable<String, Object> dados_do_pagamento = new Hashtable<String, Object>();
		dados_do_pagamento.put("var_id_pagamento", new Integer(id_pagamento));

		acesso_bd.executaUpdate(qryName, dados_do_pagamento);
		acesso_bd.fechaLigacao();
	}

	public static int devolveUltimoIdentificadorDeInsercao() throws SQLException, ClassNotFoundException, InstantiationException,
			IllegalAccessException {
		AcessoBD acesso_bd = new AcessoBD();
		acesso_bd.carregaDriverEAbreLigacao();
		String qryName = new String("devolver_ultimo_id_de_pagamento");
		ResultSet result_set = acesso_bd.executaSelect(qryName, null);
		result_set.next();
		int ultimo_id_pessoa = result_set.getInt("ultimo_id");
		acesso_bd.fechaLigacao();
		return ultimo_id_pessoa;
	}

	public static LinkedList<String> devolveTiposDePagamento() throws SQLException, ClassNotFoundException, InstantiationException,
			IllegalAccessException {

		// Consulta a BD
		AcessoBD acesso_bd = new AcessoBD();
		acesso_bd.carregaDriverEAbreLigacao();
		String qryName = new String("devolve_tipos_de_pagamento");
		ResultSet result_set = acesso_bd.executaSelect(qryName, null);
		result_set.next();

		String enum_tipos_de_pagamento = result_set.getString("type");
		LinkedList<String> tipos_de_pagamento = UtensiliosParaStrings.separaTipoEnumerado(enum_tipos_de_pagamento);

		return tipos_de_pagamento;
	}

	// Atributos
	private Factura factura;
	private int id_pagamento;
	private String tipo, numero_de_cheque, tipo_de_cartao, numero_de_cartao;
	private Date data, data_de_validade_do_cartao;
	private LinkedList<Servico> lista_de_servicos;
	public static final String NUMERARIO = "numerario";
	public static final String CHEQUE = "cheque";
	public static final String CARTAO = "cartao";
}
